package obsimpl

import (
	"bytes"
	"io"

	"github.com/astaxie/beego"
	"github.com/huaweicloud/huaweicloud-sdk-go-obs/obs"
)

var instance *obsImpl

var dynamicDir string

func SetDynamicDir(dir string) {
	dynamicDir = dir
}

func Init() error {
	cfg := Config{
		AccessKey:     beego.AppConfig.String("obs::access_key_id"),
		SecretKey:     beego.AppConfig.String("obs::secret_access_key"),
		Endpoint:      beego.AppConfig.String("obs::endpoint"),
		Bucket:        beego.AppConfig.String("obs::bucket"),
		Directory:     beego.AppConfig.String("obs::upload_cvrf_dir"),
		UpdateInfoDir: beego.AppConfig.String("obs::upload_updateinfo_dir"),
	}

	cli, err := obs.New(cfg.AccessKey, cfg.SecretKey, cfg.Endpoint)
	if err != nil {
		return err
	}

	instance = &obsImpl{
		cfg: &cfg,
		cli: cli,
	}

	return nil
}

func Instance() *obsImpl {
	return instance
}

type obsImpl struct {
	cfg *Config
	cli *obs.ObsClient
}

func (impl obsImpl) Upload(path string, data []byte) error {
	input := &obs.PutObjectInput{}
	input.Bucket = impl.cfg.Bucket
	input.Key = path
	input.Body = bytes.NewReader(data)

	_, err := impl.cli.PutObject(input)

	return err
}

func (impl obsImpl) Download(path string) ([]byte, error) {
	input := &obs.GetObjectInput{}
	input.Bucket = impl.cfg.Bucket
	input.Key = path
	output, err := impl.cli.GetObject(input)
	if err != nil {
		return nil, err
	}
	defer output.Body.Close()

	return io.ReadAll(output.Body)
}

func (impl obsImpl) GetLatestDirWithPrefix(prefix string) (string, error) {
	input := obs.ListObjectsInput{
		Bucket: impl.cfg.Bucket,
		ListObjsInput: obs.ListObjsInput{
			Prefix:    prefix,
			Delimiter: "/",
		},
	}

	out, err := impl.cli.ListObjects(&input)
	if err != nil {
		return "", err
	}

	if len(out.CommonPrefixes) == 0 {
		return "", nil
	}

	return out.CommonPrefixes[len(out.CommonPrefixes)-1], nil
}

func (impl obsImpl) ListObjects(prefix string) ([]string, error) {
	input := obs.ListObjectsInput{
		Bucket: impl.cfg.Bucket,
		ListObjsInput: obs.ListObjsInput{
			Prefix: prefix,
		},
	}

	out, err := impl.cli.ListObjects(&input)
	if err != nil {
		return nil, err
	}

	var list []string
	for _, v := range out.Contents {
		list = append(list, v.Key)
	}

	return list, nil
}
